﻿using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.WizardFramework;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace HybridLab.Workflow.Activities.UI
{
	public partial class HybridLabWizardForm : WizardForm
	{
		private IServiceProvider provider;
		private HybridLabWizardData wizardData;

		private EnvironmentPage environmentControl;
		private BuildDetailsPage buildDetailsControl;
		private DeploymentPage deploymentScriptControl;
		private TestDetailsPage testParametersControl;

		private Dictionary<Type, int> errorDictionary = new Dictionary<Type, int>();
		private bool initializing;
		private Dictionary<string, Type> pageTypeMap = new Dictionary<string, Type>();
		private Form statusForm;

		public HybridLabWizardForm(IBuildDefinition buildDef, HybridLabWorkflowDetails hybridLabSettings)
		{
			InitWizard(buildDef.BuildServer.TeamProjectCollection, buildDef.TeamProject, hybridLabSettings);
		}

		public HybridLabWizardForm(IServiceProvider provider, HybridLabWorkflowDetails hybridLabSettings)
		{
			if (provider == null)
			{
				throw new ArgumentNullException("provider");
			}
			this.provider = provider;

			IBuildDefinition service = (IBuildDefinition)provider.GetService(typeof(IBuildDefinition));
			InitWizard(service.BuildServer.TeamProjectCollection, service.TeamProject, hybridLabSettings);
		}

		private void InitWizard(TfsTeamProjectCollection tpc, string teamProject, HybridLabWorkflowDetails hybridLabSettings)
		{
			if (hybridLabSettings == null)
			{
				hybridLabSettings = new HybridLabWorkflowDetails();
			}
			wizardData = new HybridLabWizardData(tpc, teamProject, hybridLabSettings);

			wizardData.EnvironmentDetails.ErrorChanged += new EventHandler(ErrorChangedHandler);
			wizardData.BuildDetails.ErrorChanged += new EventHandler(ErrorChangedHandler);
			wizardData.DeploymentDetails.ErrorChanged += new EventHandler(ErrorChangedHandler);
			wizardData.TestDetails.ErrorChanged += new EventHandler(ErrorChangedHandler);
			wizardData.DataLoadCompleted += new EventHandler(wizardData_DataLoadCompleted);
			wizardData.DataLoadFailed += new EventHandler(wizardData_DataLoadFailed);
			SetWizardProperties();
			LoadWizardPages();
		}

		internal bool CanDeactivatePage(string pageId)
		{
			if (pageTypeMap.ContainsKey(pageId))
			{
				Type key = pageTypeMap[ActivePage.Id];
				if (errorDictionary.ContainsKey(key))
				{
					return (errorDictionary[key] == 0);
				}
			}
			return true;
		}

		internal void CheckAndSetButtonState()
		{
			if (!initializing)
			{
				EnableButton(ButtonType.Finish, errorDictionary.Values.All(v => v == 0));
				EnableButton(ButtonType.Next, CanDeactivatePage(ActivePage.Id) && !IsLastPage());
			}
		}

		private void DisposeStatusForm()
		{
			if (statusForm != null)
			{
				statusForm.Close();
				statusForm.Dispose();
				statusForm = null;
			}
		}

		private void ErrorChangedHandler(object sender, EventArgs args)
		{
			if (sender != null)
			{
				Type type = sender.GetType();
				PropertyErrorManager manager = sender as PropertyErrorManager;
				if (manager != null)
				{
					errorDictionary[type] = manager.TotalInvalidProperties;
				}
			}
			CheckAndSetButtonState();
		}

		private bool IsLastPage()
		{
			return (NextPage == null);
		}

		private void LoadWizardPages()
		{
			var welcomePage = new HybridLabWizardPage(this, new WelcomePage(), null, "Welcome to the Notion Physical Workflow Configuration Wizard", "Welcome");
			AddPage(welcomePage);

			environmentControl = new EnvironmentPage(wizardData);
			var environmentPage = new HybridLabWizardPage(this, environmentControl, null, "Select the Physical Environment to deploy to and test on", "Select Environment");
			AddPage(environmentPage);
			pageTypeMap.Add(environmentPage.Id, typeof(EnvironmentDetailsEx));

			buildDetailsControl = new BuildDetailsPage(wizardData);
			var buildPage = new HybridLabWizardPage(this, buildDetailsControl, null, "Configure the Build to deploy and test", "Configure Build");
			AddPage(buildPage);
			pageTypeMap.Add(buildPage.Id, typeof(BuildDetailsEx));

			deploymentScriptControl = new DeploymentPage(wizardData);
			var deployScriptPage = new HybridLabWizardPage(this, deploymentScriptControl, null, "Configure deployment scripts for the environment", "Deployment Scripts");
			AddPage(deployScriptPage);
			pageTypeMap.Add(deployScriptPage.Id, typeof(DeploymentDetailsEx));

			testParametersControl = new TestDetailsPage(wizardData);
			var testParamPage = new HybridLabWizardPage(this, testParametersControl, null, "Configure test settings", "Configure Testing");
			AddPage(testParamPage);
			pageTypeMap.Add(testParamPage.Id, typeof(RunTestDetailsEx));
		}

		private void wizardData_DataLoadCompleted(object sender, EventArgs e)
		{
			DisposeStatusForm();
			initializing = false;
			CheckAndSetButtonState();
		}

		private void wizardData_DataLoadFailed(object sender, EventArgs e)
		{
			DisposeStatusForm();
			initializing = false;
			DataLoadFailedEventArgs args = (DataLoadFailedEventArgs)e;
			ShowErrorDialog(args.Reason.Message);
			Close();
		}

		internal static void ShowErrorDialog(string errorMessage)
		{
			MessageBox.Show(errorMessage, "Physical Workflow Parameters", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
		}

		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			DisposeStatusForm();
		}

		public override void OnFinish()
		{
			base.OnFinish();
			DialogResult = DialogResult.OK;
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			initializing = true;
			EnableButton(ButtonType.Finish, false);
			EnableButton(ButtonType.Next, false);
			EnableButton(ButtonType.Previous, false);
			ShowStatusForm();
			wizardData.Initialize();
		}

		private void SetWizardProperties()
		{
			HelpButton = true;
			MinimizeBox = false;
			MaximizeBox = false;
			ShowIcon = false;
			ShowInTaskbar = false;
			StartPosition = FormStartPosition.CenterParent;
			Title = "Hybrid Lab Workflow Wizard";
			MinimumSize = new Size(880, 680);
			MaximumSize = new Size(880, 680);
			ShowOrientationPanel = true;
			OrientationPanelStepMode = Microsoft.WizardFramework.OrientationPanelStepMode.Automatic;
		}

		private void ShowStatusForm()
		{
			DisposeStatusForm();
			statusForm = new BusyIndicator();
			statusForm.StartPosition = FormStartPosition.Manual;
			int x = (Location.X + (Width / 2)) - (statusForm.Width / 2);
			int y = (Location.Y + (Height / 2)) - (statusForm.Height / 2);
			statusForm.Location = new Point(x, y);
			statusForm.Owner = this;
			statusForm.Show();
			statusForm.BringToFront();
		}

		public HybridLabWorkflowDetails WorkflowDetails
		{
			get
			{
				return wizardData.GetWorkflowDetails();
			}
		}
	}
}
